
#ifndef __KinectSkeleton_h__
#define __KinectSkeleton_h__

#include "NuiApi.h"
#include "NuiDataType.h"

#include <sapi.h>
#include <sphelper.h>
#include <Shlobj.h>
#include <dmo.h>
#include <windows.h>

#include "KinectAudioStream.h"

// For configuring DMO properties
#include <wmcodecdsp.h>

// For FORMAT_WaveFormatEx and such
#include <uuids.h>

#pragma comment ( lib, "d2d1.lib" )


namespace NuiManager 
{
	/*
		Wrapper class to bridge Kinect API and other C++ program
	*/
	class KinectManager
	{
		static const NUI_IMAGE_RESOLUTION cDepthResolution = NUI_IMAGE_RESOLUTION_640x480;
		// green screen background will also be scaled to this resolution
		static const NUI_IMAGE_RESOLUTION cColorResolution = NUI_IMAGE_RESOLUTION_640x480;
	public:
		KinectManager(void);
		virtual ~KinectManager(void);

		HRESULT InitNui(void);
		void UnInitNui(void);

		void InitializeAudioSystem();
		
		size_t getDeviceCount(void);

		BYTE* getColorBuffer();
		BYTE* getDepthBuffer();
		BYTE* getPersonMaskBuffer();
		NUI_SKELETON_DATA* getSkeleton(int index = 0);

		int getSoundEvent();

	protected:
		INuiSensor*         nuiSensor;
		BSTR                instanceId;

		BYTE*				depthBuffer;
		BYTE*				personMaskBuffer;
		BYTE*				colorBuffer;
		NUI_SKELETON_DATA*	nuiSkeletonData;
		BYTE*               m_colorRGBX;
		BYTE*               m_outputRGBX;
	protected:
		bool trackColorImage(void);
		bool trackDepthImage(void);
		bool trackSkeleton(void);

	private:
		DWORD WINAPI            nuiProcessThread();
		static DWORD WINAPI     nuiProcessThread(LPVOID pParam);

		HRESULT InitAudioStream();
		HRESULT CreateSpeechRecognizer();
		HRESULT LoadSpeechGrammar();
		HRESULT StartSpeechRecognition();
		int ProcessSpeech();
		int MapSpeechTagToAction(LPCWSTR pszSpeechTag);

	private:
		HANDLE        hThNuiProcess;
		HANDLE        hEvNuiProcessStop;

		HANDLE        hNextDepthFrameEvent;
		HANDLE        hNextColorFrameEvent;
		HANDLE        hNextSkeletonEvent;
		HANDLE        pDepthStreamHandle;
		HANDLE        pVideoStreamHandle;

		DWORD         lastDepthFPStime;
		DWORD         lastSkeletonFoundTime;

		int           depthFramesTotal;
		int           lastDepthFramesTotal;
		int			  frameRate;

		LONG		  m_depthWidth;
		LONG		  m_depthHeight;
					  
		LONG		  m_colorWidth;
		LONG		  m_colorHeight;

		LONG          m_colorToDepthDivisor;

		USHORT*       m_depthD16;
		LONG*         m_colorCoordinates;

	private:
		static LPCWSTR          GrammarFileName;

		// Stream given to speech recognition engine
		ISpStream*              m_pSpeechStream;

		// Audio stream captured from Kinect.
		KinectAudioStream*      m_pKinectAudioStream;
		
		// Format of Kinect audio stream
		static const WORD       AudioFormat = WAVE_FORMAT_PCM;

		// Number of channels in Kinect audio stream
		static const WORD       AudioChannels = 1;

		// Samples per second in Kinect audio stream
		static const DWORD      AudioSamplesPerSecond = 16000;

		// Average bytes per second in Kinect audio stream
		static const DWORD      AudioAverageBytesPerSecond = 32000;

		// Block alignment in Kinect audio stream
		static const WORD       AudioBlockAlign = 2;

		// Bits per audio sample in Kinect audio stream
		static const WORD       AudioBitsPerSample = 16;

		// Speech recognizer
		ISpRecognizer*          m_pSpeechRecognizer;

		// Speech recognizer context
		ISpRecoContext*         m_pSpeechContext;

		// Speech grammar
		ISpRecoGrammar*         m_pSpeechGrammar;

		// Event triggered when we detect speech recognition
		HANDLE                  m_hSpeechEvent;
	};
}

#endif